using System;
using System.Collections.Generic;
namespace Framework.Core
{
    public class Timer
    {
        private static readonly CustomPool<TimerTaskBase> _pool = new(() => new TimerTaskBase());
        private int _tag = 0;
        private readonly List<TimerTaskBase> _executeList = new List<TimerTaskBase>();
        private readonly Dictionary<int, TimerTaskBase> _map = new Dictionary<int, TimerTaskBase>();

        private List<TimerTaskBase> _addList = new List<TimerTaskBase>();
        private readonly List<int> _removeList = new List<int>();

        public void Update(float deltaTime, float unscaledDeltaTime)
        {
            int len;
            len = _removeList.Count;
            if (len > 0)
            {
                while (len-- > 0)
                {
                    var tag = _removeList[len];
                    RemoveTask(tag);
                }
                _removeList.Clear();
            }
            len = _addList.Count;
            if (len > 0)
            {
                while (len-- > 0)
                {
                    var task = _addList[len];
                    AddTask(task);
                }
                _addList.Clear();
            }
            len = _executeList.Count;
            while (len-- > 0)
            {
                var task = _executeList[len];
                if (!task.Execute(deltaTime, unscaledDeltaTime))
                {
                    _executeList.RemoveAt(len);
                    RemoveTask(task);
                }
            }
        }
        public int Start(float interval, Action callback, int loop = 1, bool unscaledDeltaTime = true)
        {
            var task = _pool.Get();
            task.Clear();
            task.Init(_tag++, interval, callback, loop, unscaledDeltaTime);
            _addList.Add(task);
            return task.Tag;
        }
        public void Stop(int tag)
        {
            _removeList.Add(tag);
        }
        private void RemoveTask(TimerTaskBase task)
        {
            if (_map.ContainsKey(task.Tag))
            {
                _map.Remove(task.Tag);
                _pool.Release(task);
            }
        }
        private void RemoveTask(int tag)
        {
            if (_map.ContainsKey(tag))
            {
                var task = _map[tag];
                _executeList.Remove(task);
                _map.Remove(tag);
                _pool.Release(task);
            }
        }
        private bool AddTask(TimerTaskBase task)
        {
            if (_map.ContainsKey(task.Tag)) return false;
            _map.Add(task.Tag, task);
            _executeList.Add(task);
            return true;
        }
        public void Clear()
        {
            var len = _addList.Count;
            if (len > 0)
            {
                while (len-- > 0)
                {
                    var item = _addList[len];
                    _pool.Release(item);
                }
                _addList.Clear();
            }
            len = _executeList.Count;
            if (len > 0)
            {
                while (len-- > 0)
                {
                    var item = _executeList[len];
                    _pool.Release(item);
                }
                _executeList.Clear();
            }
            _removeList.Clear();
            _map.Clear();
        }
    }

    internal class TimerTaskBase
    {
        public int Tag { get; private set; }
        protected float _interval;
        protected float _currentTime;
        protected Action _callback;
        protected int _loop;
        protected bool _unscaledDeltaTime;
        public void Clear()
        {
            Tag = 0;
            _interval = 0;
            _currentTime = 0;
            _callback = null;
        }
        public void Init(int tag, float interval, Action callback, int loop = 0, bool unscaledDeltaTime = true)
        {
            if (this.Tag > 0 || interval <= 0f) return;
            this.Tag = tag;
            this._interval = interval;
            _currentTime = 0;
            _callback = callback;
            if (loop < 0)
            {
                loop = 0;
            }
            _loop = loop;
        }
        public bool Execute(float deltaTime, float unscaledDeltaTime)
        {
            _currentTime += _unscaledDeltaTime ? unscaledDeltaTime : deltaTime;
            while (_currentTime >= _interval)
            {
                _currentTime -= _interval;
                if (_loop > 0)
                {
                    _loop--;
                    try
                    {
                        _callback?.Invoke();
                    }
                    catch (System.Exception )
                    {
                        //中断
                        return false;
                    }
                    if (_loop < 1)
                    {
                        //中断
                        return false;
                    }
                }
                else
                {
                    _loop--;
                    try
                    {
                        _callback?.Invoke();
                    }
                    catch (System.Exception )
                    {
                        return false;
                    }

                }
            }
            //断续执行
            return true;
        }
    }
}